#include <vector>
#include <queue>
#include "sched_mfq.h"
#include "basesched.h"

#include <iostream>
#include <fstream>

using namespace std;

SchedMFQ::SchedMFQ(vector<int> argn) {
	// MFQ recibe los n quantums por parámetro
	// Me guardo los quantums (vienen como n enteros uno atras del otro)
	colas = vector<queue<int> >(argn.size());
	quantums = vector<int>(argn.size());
	cantColas = argn.size();
	
	for(int i=0; i<(int)argn.size(); i++)
	{
		quantums[i] = argn[i];
		queue<int> cola;
		colas[i] = cola;
	}
}

void SchedMFQ::load(int pid) {
	// Cuando llega una tarea se guarda en la cola de mayor prioridad
	// Almaceno ademas la prioridad asignada en el diccionario
	(colas[PRIORIDAD_MAX]).push(pid);
	prioridades[pid] = PRIORIDAD_MAX;
}

void SchedMFQ::unblock(int pid) {
	// Se reencola al final de la cola inmediatamente de superior prioridad (si hay)
	int i = prioridades[pid]; // Cola en la que estaba el proceso
	
	// Si hay cola de prioridad superior (es decir si no estoy en la de mayor prioridad)
	if (i != PRIORIDAD_MAX)
	{
		colas[i-1].push(pid);
		// Actualizo el valor en prioridades
		prioridades[pid] = i - 1;
	}
	else
	{
		(colas[PRIORIDAD_MAX]).push(pid);
	}

}

int SchedMFQ::tick(const enum Motivo m) {

	int primerColaNoVacia = primeraNoVacia();

	
	// El proceso termino busco el siguiente a ser ejecutado
	if (m == EXIT) {

		if (primerColaNoVacia == -1) 
			return IDLE_TASK;
		else {
				int sig = colas[primerColaNoVacia].front(); colas[primerColaNoVacia].pop();
				quantumUtilizado = 0;
				return sig;
			}
	}

	// Si se bloquea busca la siguente, si no hay sigue executando la actual			
	if(m == BLOCK) {
	
		if (primerColaNoVacia == -1) 
			return IDLE_TASK;
		else {
			int sig = colas[primerColaNoVacia].front(); colas[primerColaNoVacia].pop();
			quantumUtilizado = 0;
			return sig;
		}
	} 
	



	
	// Si estoy en el primer caso que es IDLE_TASK...
	if(current_pid() == IDLE_TASK) {
		if (primerColaNoVacia == -1) 
			return IDLE_TASK;
		else {
				int sig = colas[primerColaNoVacia].front(); colas[primerColaNoVacia].pop();
				quantumUtilizado = 0;
				return sig;
		}
	}


	// Estoy en tick. Si se le acabo el quantum
	
	int prioridadActual = prioridades[current_pid()];
		
	//Si se me acabo el quantum
	if(quantumUtilizado >=  quantums[prioridadActual] - 1)
	{
		
	
		if(primerColaNoVacia == -1)
			return current_pid();
	
		// Si hay una cola de menor prioridad lo pasamos ahi
		if (prioridadActual != cantColas - 1){
			prioridadActual++;
			
		}
							
		prioridades[current_pid()] = prioridadActual;
		colas[prioridadActual].push(current_pid());

		primerColaNoVacia = primeraNoVacia();
		int sig = colas[primerColaNoVacia].front(); colas[primerColaNoVacia].pop();
		quantumUtilizado = 0;
		return sig;


	}
	//Si todavia tengo quantum
	else
	{
			
		quantumUtilizado++;
		return current_pid();
	}
	
	
}

int SchedMFQ::primeraNoVacia() {
        for(int i=0;i<cantColas;i++)
        {
			if(!colas[i].empty())
				return i;
        }
        return -1;
}
